package com.piccolo.wrapper.client.sample;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.piccolo.wrapper.client.component.PActivity;
import com.piccolo.wrapper.client.component.PBounds;
import com.piccolo.wrapper.client.component.PCamera;
import com.piccolo.wrapper.client.component.PCanvas;
import com.piccolo.wrapper.client.component.PShape;
import com.piccolo.wrapper.client.component.PImage;
import com.piccolo.wrapper.client.component.PLayer;
import com.piccolo.wrapper.client.component.PActivityScheduler;
import com.piccolo.wrapper.client.component.PNode;
import com.piccolo.wrapper.client.component.PText;
import com.piccolo.wrapper.client.component.PTransform;
import com.piccolo.wrapper.client.component.PShape.Shape;
import com.piccolo.wrapper.client.event.PInputEvent;
import com.piccolo.wrapper.client.handler.PBasicInputEventHandler;

public class Sample extends VerticalPanel
{
	private static final int COLOUR_COUNT = 100;
	private static final String[] COLOURS = createColours(COLOUR_COUNT);

	public Sample() 
	{ 
		final VerticalPanel main = new VerticalPanel();
		main.setSpacing(5);

		final ListBox selector = new ListBox();

		selector.addItem("Hierarchy");
		selector.addItem("Events");
		selector.addItem("Sticky nodes");
		selector.addItem("Images");
		selector.addItem("Circles");
		selector.addItem("Triangles");

		selector.setVisibleItemCount(6);

		main.add(selector);

		selector.addChangeHandler(new ChangeHandler(){
			public void onChange(ChangeEvent event)
			{
				PCanvas canvas = new PCanvas(600, 400);
				PCamera camera = canvas.getCamera();
				PLayer layer = camera.getLayers().get(0);
				PActivityScheduler scheduler = camera.getRoot().getScheduler();

				if (selector.getSelectedIndex() == 0)
					hierarchy(camera, layer, scheduler);
				else if (selector.getSelectedIndex() == 1)
					events(camera, layer);
				else if (selector.getSelectedIndex() == 2)
					stickyNodes(camera, layer, scheduler);
				else if (selector.getSelectedIndex() == 3)
					images(layer, scheduler);
				else if (selector.getSelectedIndex() == 4)
					circles(camera, layer);
				else if (selector.getSelectedIndex() == 5)
					triangles(camera, layer);

				if (main.getWidgetCount() > 1)
					main.remove(1);
				main.add(canvas);
			}});

		PCanvas canvas = new PCanvas(600, 400);
		PCamera camera = canvas.getCamera();
		PLayer layer = camera.getLayers().get(0);
		PActivityScheduler scheduler = camera.getRoot().getScheduler();
		hierarchy(camera, layer, scheduler);

		main.add(canvas);
		RootPanel.get().add(main);
	}

	private void triangles(PCamera camera, PLayer layer) 
	{
		int c = 0;
		for (int x = 0; x < 10; x++) 
		{
			PShape node = new PShape(Shape.TRIANGLE, COLOURS[c++], new PBounds(120, 10 + x * 10, 200, 180 - x * 10));
			layer.addChild(node);
		}

		layer.addClickListener(new PBasicInputEventHandler() 
		{
			public void mouseClicked(PInputEvent event) 
			{
				PNode clickedNode = event.getPickedNode();
				clickedNode.moveToBack();
			}
		});
	}

	private void circles(final PCamera camera, PLayer layer)
	{
		int c = 0;
		for (int x = 0; x < 10; x++) 
		{
			for (int y = 0; y < 10; y++) 
			{
				PShape node = new PShape(Shape.CIRCLE, COLOURS[c++], new PBounds(x, y, 100, 100));
				node.scale(0.25);
				node.translate(30 * x + 1.25, 30 * y + 1.25);
				layer.addChild(node);
			}
		}

		layer.addClickListener(new PBasicInputEventHandler() 
		{
			public void mouseClicked(PInputEvent event) 
			{
				PNode clickedNode = event.getPickedNode();
				PTransform globalTransform = clickedNode.getGlobalTransform();
				PBounds focusBounds = clickedNode.getGlobalFullBounds();
				PTransform inverse = globalTransform.getInverse();
				double targetX = (camera.getBounds().getWidth() - focusBounds.getWidth() / clickedNode.getDisplayScale()) / 2;
				double targetY = (camera.getBounds().getHeight() - focusBounds.getHeight() / clickedNode.getDisplayScale()) / 2;          
				inverse.translate(targetX, targetY);
				camera.animateViewToTransform(inverse, 500);
			}
		});
	}

	private void images(final PLayer layer, PActivityScheduler scheduler) 
	{
		PImage node = new PImage("http://www.piccolo2d.org/images/Piccolo2D-Logo-small.png", new PBounds(0, 0, 100, 100));
		layer.addChild(node);

		scheduler.schedule(new PActivity()
		{
			public void activityStep(double ellapsed) 
			{
				double cos = -Math.cos(ellapsed / 800);
				PTransform transformation = new PTransform();
				transformation.scale(cos * 1.5 + 1.5);
				transformation.translate(200 + 200 * cos, 0);
				transformation.rotate(cos - 100);
				layer.setTransform(transformation);  
			}
		});
	}

	private void events(final PCamera camera, PLayer layer) 
	{
		int c = 0;
		for (int x = 0; x < 10; x++) 
		{
			for (int y = 0; y < 10; y++) 
			{
				PNode node = new PNode(COLOURS[c++], new PBounds(0, 0, 100, 100));
				node.scale(0.25);
				node.translate(30 * x + 1.25, 30 * y + 1.25);
				layer.addChild(node);
			}
		}

		layer.addClickListener(new PBasicInputEventHandler() 
		{
			public void mouseClicked(PInputEvent event) 
			{
				PNode clickedNode = event.getPickedNode();
				PTransform globalTransform = clickedNode.getGlobalTransform();
				PBounds focusBounds = clickedNode.getGlobalFullBounds();
				PTransform inverse = globalTransform.getInverse();
				double targetX = (camera.getBounds().getWidth() - focusBounds.getWidth() / clickedNode.getDisplayScale()) / 2;
				double targetY = (camera.getBounds().getHeight() - focusBounds.getHeight() / clickedNode.getDisplayScale()) / 2;          
				inverse.translate(targetX, targetY);
				camera.animateViewToTransform(inverse, 500);
			}
		});
	}

	private void hierarchy(final PCamera camera, final PLayer layer, PActivityScheduler scheduler) 
	{
		PNode parent = layer;
		int displayScale = 1;

		for (int i = 0; i < COLOUR_COUNT; i++) 
		{
			PNode newChild = new PNode(COLOURS[i], new PBounds(0, 0, 300, 300));
			newChild.scale(0.1);
			newChild.translate(135, 135);
			newChild.setDisplayScale(displayScale);

			displayScale *= 10;

			parent.addChild(newChild);
			parent = newChild;
		}

		PNode lastNode = new PText("That's all folks");
		lastNode.setDisplayScale(displayScale);
		parent.addChild(lastNode);

		PNode topChild = layer.getChildren().get(0);
		topChild.translate(-135, -135);
		topChild.scale(10);

		layer.addClickListener(new PBasicInputEventHandler() 
		{
			public void mouseClicked(PInputEvent event) 
			{
				PNode clickedNode = event.getPickedNode();
				PTransform globalTransform = clickedNode.getGlobalTransform();
				PTransform inverse = globalTransform.getInverse();     
				camera.animateViewToTransform(inverse, 500);
			}
		});
	}

	private void stickyNodes(PCamera camera, final PLayer layer, PActivityScheduler scheduler) 
	{
		PText text = new PText("Hello World!", COLOURS[0]);
		camera.addChild(text);

		PText layerNode = new PText("Goodbye World.");
		layerNode.translate(0, 25);  

		layer.addChild(layerNode); 

		scheduler.schedule(new PActivity()
		{
			public void activityStep(double ellapsed) 
			{
				double cos = -Math.cos(ellapsed / 800);
				PTransform transformation = new PTransform();
				transformation.scale(cos * 2.5 + 3.5);
				transformation.translate(200 + 200 * cos, 0);
				layer.setTransform(transformation);  
			}
		});
	}

	private static String[] createColours(int size) 
	{
		String[] colours = new String[size];
		for (int i = 0; i < size; i++)
		{
			long r = Math.round(Math.random() * 255);  
			long g = Math.round(Math.random() * 255);  
			long b = Math.round(Math.random() * 255);  
			colours[i] =  "rgb(" + r + "," + g + "," + b + ")";
		}
		return colours;
	}
}
